// 获取小数位的长度
function digitLen(num: number) {
  const decimal = num.toString().split('.')[1];
  if (decimal) return decimal.length;
  return 0;
}
function calc(a: number, operation: string, b: number) {
  // 算出最小的，能将两个数转换为整数的10的次方
  const common = 10 ** Math.max(digitLen(a), digitLen(b));
  let res: number = 0;
  switch (operation) {
    case '+': {
      // 加
      res = (a * common + b * common) / common;
      break;
    }
    case '-': {
      // 减
      res = (a * common - b * common) / common;
      break;
    }
    case '*': {
      // 乘
      res = (a * common * (b * common)) / common ** 2;
      break;
    }
    case '/': {
      // 除
      res = (a * common) / (b * common);
      break;
    }
  }
  // 利用toFixed四舍五入，解决类似：(0.11*100*1.1*100)/10000 计算不准确的问题（某些浮点数乘10精度错误）
  return Number.parseFloat(res.toFixed(12));
}

// // 测试代码
// let res = calc(1.11, '*', 10)
// console.log(res)

function parseExpression(s: any) {
  s = `${s.replaceAll(/\s/g, '')}e`; // 去除所有空格，末尾加上一个结束符号,确保最后一个数加入到栈中
  const stack: Array<number> = [];
  let preSign = '+'; // 初始置为+，目的：让第一个数字入栈
  let curNum = 0; // 当前数字
  const reg = /\\d|./;
  for (const element of s) {
    if (reg.test(element)) {
      // 当前字符为数字或点，拼接数字
      curNum = curNum + element;
    } else {
      // 当前字符是操作符，则判断运算上一符号
      if (preSign === '+') {
        stack.push(curNum);
      } else if (preSign === '-') {
        const last = stack[stack.length - 1];
        if (last === 0 && 1 / last < 0) {
          // 判断上一个数字是不是 -0，解决类似：2--7这种问题
          stack.push(curNum);
        } else {
          stack.push(-1 * curNum);
        }
      } else if (['+', '-'].includes(element) && !curNum) {
        // 对数字的正负号做特殊处理 比如：2*-2
        if (['+', '-'].includes(`${curNum}`)) return 0; // 2*--2 有两个减号，直接返回 0
        curNum = element;
        continue;
      } else if (preSign === '*') {
        stack.push(calc(stack.pop() as number, preSign, curNum)); // calc方法是用于解决js计算精度的方法，可参考我的另外一篇文章
      } else if (preSign === '/') {
        stack.push(calc(stack.pop() as number, preSign, curNum));
      } else {
        return 0; // 既不是数字也不是符号也不是点，直接返回0
      }
      curNum = 0; // 运算后将curNum置为0
      preSign = element; // 记录当前符号
    }
  }
  // eslint-disable-next-line unicorn/no-array-reduce
  let sum = stack.reduce((pre, num) => calc(pre, '+', num), 0); // 计算栈的和
  if (Number.isNaN(sum) || !Number.isFinite(sum)) sum = 0; // 如果结果是NaN,或者无穷，就置为0
  return sum;
}

export default parseExpression;

// test
// console.log(parseExpression('3.1 - 2 + 3 * 4 - 4 / 2'))   // 11.1
